package main

import (
	"fmt"
	"github.com/prometheus/client_golang/prometheus/promhttp"
	log "github.com/sirupsen/logrus"
	"github.com/spf13/pflag"
	"go.uber.org/zap"
	"google.golang.org/grpc"
	"net"
	"net/http"
	"qabx.net/common"
	"qabx.net/common/clients/ttl"
	"qabx.net/common/utils/decode"
	logInit "qabx.net/common/utils/log"
	"qabx.net/safe-app-center/api/device_os_api"
	leak "qabx.net/safe-app-center/api/leak"
	"qabx.net/safe-app-center/api/security_center_api"
	"qabx.net/safe-app-center/pkg/config/constants"
	env "qabx.net/safe-app-center/pkg/config/env"
	"qabx.net/safe-app-center/pkg/crontab"
	"qabx.net/safe-app-center/pkg/handler/device_os"
	"qabx.net/safe-app-center/pkg/handler/leak_handler"
	"qabx.net/safe-app-center/pkg/handler/security_center"
	"qabx.net/safe-app-center/pkg/monitor"
	"qabx.net/safe-app-center/pkg/utils"
)

var (
	safeAppCenterServer = pflag.String("safeAppCenterUrl", "0.0.0.0:31114", "security ability server listen")
	redisUrl            = pflag.String("redisStr", "192.168.2.211:6379", "redis connection")
	redisPassword       = pflag.String("redisPassword", "GTS0je4P65vy+Kt88ZOaZZCwLEu1wDhS7b0dLef0TkI=", "redis password")
	redisDB             = pflag.Int("redisDB", 1, "redis db")
	//dbURL               = pflag.String("dbURL", "host=192.168.2.220 port=5432 user=postgres password=qabx666 dbname=safe-mgr sslmode=disable", "db connect url")

	dbUsername = pflag.String("dbUsername", "postgres", "pgsql db username")
	dbPassword = pflag.String("dbPassword", "GTS0je4P65vy+Kt88ZOaZQdyx+avipL7tx3UCU5G/5s=", "pgsql db password")
	dbHost     = pflag.String("dbHost", "192.168.2.220", "pgsql db host")
	dbPort     = pflag.String("dbPort", "5432", "pgsql db port")
	dbDatabase = pflag.String("dbDatabase", "safe-mgr", "pgsql db database")

	dbDriver    = pflag.String("dbDriver", "postgres", "db driver: mysql postgres oci8")
	dbSchema    = pflag.String("dbSchema", "", "db Schema")
	runMode     = pflag.String("runMode", "debug", "run mode")
	reportUrl   = pflag.String("reportUrl", "127.0.0.1:9093", "report server url")
	logLevelStr = pflag.String("logLevelStr", "info", "log level str")
	//
	//cronTime = pflag.Int64("cronTime", 30, "default  cron  time to 30 seconds")
	////edgeSecurityUrl     = pflag.String("edgeSecurityUrl", "172.90.4.140:7777", "edge security server listen")
	////certFile            = pflag.String("edgeSecurityCertFile", "/data/8647391_zjyk.qabx.net.pem", "cert file addr")
	//
	//heartCronTime = pflag.Int64("heartCronTime", 60, "default heart cron  time to 60 seconds")
	//
	////featureFilePath = pflag.String("featureFilePath", "../config/feature.cfg", "feature file path")
	////featureVersion  = pflag.String("featureVersion", "", "feature version")
	////featureUpdate   = pflag.Int64("featureUpdate", 9999, "feature update")
	//netflowOfflineTime = pflag.Int64("netflowOfflineTime", 300, "default netflow offline time") //netflow设备离线时间

	//监控暴露地址
	monitorUrl = pflag.String("monitorUrl", "0.0.0.0:10109", "监控暴露地址")
)

var tcpLogger *log.Entry

func main() {
	pflag.Parse()

	constants.REPORT_URL = *reportUrl
	//constants.EDGE_SECURITY_URL = *edgeSecurityUrl
	//constants.EDGE_SECURITY_CERT_FILE = *certFile

	logLevel, err := log.ParseLevel(*logLevelStr)
	if err != nil {
		fmt.Println("log level parse failed", err.Error())
		return
	}
	logInit.InitLogFile("safe-app-center", logLevel)
	mixStr, err := decode.GetDefaultMixStr()
	tcpLogger = log.WithFields(log.Fields{
		"app": "safe-app-center",
	})

	ttl.SetLogger(log.StandardLogger())
	RedisAuth, err := decode.DecodeCBC(*redisPassword, mixStr)
	if err != nil {
		tcpLogger.Error("please input right redis password")
		return
	}

	err = utils.TTLOperator.InitClient(*redisUrl, RedisAuth, *redisDB)
	if err != nil {
		tcpLogger.Errorf("redis connect fail: %s", err.Error())
		return
	}

	initDbConfig()

	initConfig()
	pwd, err := decode.DecodeCBC(*dbPassword, mixStr)
	if err != nil {
		tcpLogger.Errorf("please input right db password: %s", err.Error())
		return
	}
	env.DbOptions.DbPassword = pwd
	utils.Init()

	//判断特征库是否存在
	featureVersionKey := fmt.Sprintf("%s", constants.REDIS_KEY_FEATURE_VERSION)

	version, err := utils.TTLOperator.LIndex(featureVersionKey, 0)
	if err != nil && len(version) > 0 {
		log.Errorf("please init feature version")
		return
	}
	//utils.NetR1un()
	//return
	//初始化监控
	registry := monitor.InitMonitorRegister()

	go func() {
		http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{Registry: registry}))
		err := http.ListenAndServe(*monitorUrl, nil)
		if err != nil {
			tcpLogger.Panic("monitor init failed", zap.Error(err))
			return
		}
	}()

	server := grpc.NewServer(grpc.UnaryInterceptor(monitor.UnaryInterceptor))

	securityServerImpl := &security_center.SecurityCenterServer{}
	security_center_api.RegisterSecurityCenterApiServiceServer(server, securityServerImpl)

	deviceOsImpl := &device_os.DeviceOsServerImpl{}
	device_os_api.RegisterDeviceOsApiServiceServer(server, deviceOsImpl)

	reportServiceServerImpl := &leak_handler.ReportServiceServerImpl{}
	leak.RegisterReportServiceServer(server, reportServiceServerImpl)

	cron := crontab.CronTab{}

	go cron.StartCronJob()

	go func() {
		lis, err := net.Listen("tcp", *safeAppCenterServer)
		if err != nil {
			log.Errorf("grpc server tcp create failed: %s", err.Error())
			return
		}
		tcpLogger.Infof("grpc server listen %s", *safeAppCenterServer)
		server.Serve(lis)
	}()

	select {}
}

func initDbConfig() {
	env.DbOptions = &env.DbConfig{
		RunMode:  utils.SetEnvStr(*runMode, "GIN_MODE"),
		DbDriver: utils.SetEnvStr(*dbDriver, "DB_DRIVER"),
		DbSchema: utils.SetEnvStr(*dbSchema, "DB_SCHEMA"),

		DbHost:     utils.SetEnvStr(*dbHost, "DB_HOST"),
		DbDatabase: utils.SetEnvStr(*dbDatabase, "DB_DATABASE"),
		DbPassword: utils.SetEnvStr(*dbPassword, "DB_PASSWORD"),
		DbUsername: utils.SetEnvStr(*dbUsername, "DB_USERNAME"),
		DbPort:     utils.SetEnvStr(*dbPort, "DB_PORT"),
	}
}

func initConfig() {
	//初始化redis配置
	prometheusCronTimeKey := fmt.Sprintf("%s:%s", constants.SECUIRTY_CENTER, constants.PROMETHEUS_CRON_TIME)
	prometheusCronTimeStr, _ := utils.TTLOperator.Get(prometheusCronTimeKey)
	if len(prometheusCronTimeStr) == 0 {
		//默认30秒
		prometheusCronTimeStr = "30"
		_ = utils.TTLOperator.SetV(prometheusCronTimeKey, prometheusCronTimeStr, -1)
	}

	heartCronTimeKey := fmt.Sprintf("%s:%s", constants.SECUIRTY_CENTER, constants.HEART_CRON_TIME)
	heartCronTimeStr, _ := utils.TTLOperator.Get(heartCronTimeKey)
	if len(heartCronTimeStr) == 0 {
		//默认60秒 按秒来算可以超过60
		heartCronTimeStr = "60"
		_ = utils.TTLOperator.SetV(heartCronTimeKey, heartCronTimeStr, -1)
	}

	netflowOfflineTimeKey := fmt.Sprintf("%s:%s", constants.SECUIRTY_CENTER, constants.NETFLOW_OFFLINE_TIME)
	netflowOfflineTimeStr, _ := utils.TTLOperator.Get(netflowOfflineTimeKey)
	if len(netflowOfflineTimeStr) == 0 {
		//默认300秒
		netflowOfflineTimeStr = "300"
		_ = utils.TTLOperator.SetV(netflowOfflineTimeKey, netflowOfflineTimeStr, -1)
	}
	prometheusCronTime, _ := common.StringToInt64(prometheusCronTimeStr)
	heartCronTime, _ := common.StringToInt64(heartCronTimeStr)
	netflowOfflineTime, _ := common.StringToInt64(netflowOfflineTimeStr)

	env.Options = &env.Config{
		PrometheusCronTime: prometheusCronTime,
		HeartCronTime:      heartCronTime,
		NetflowOfflineTime: netflowOfflineTime,
	}
}
